package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.dto.leanring.PointsRecordMsgDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.entity.SignRecord;
import com.tianji.learning.mapper.SignRecordMapper;
import com.tianji.learning.pojo.PointsRecordType;
import com.tianji.learning.service.ISignRecordService;
import com.tianji.learning.vo.SignResultVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

import static com.tianji.common.constants.MqConstants.Exchange.LEARNING_EXCHANGE;
import static com.tianji.common.constants.MqConstants.Key.POINT_RECORD_KEY;
import static com.tianji.common.constants.RedisConstants.SIGN_RECORD_KEY;

/**
 * <p>
 * 签到记录表 服务实现类
 * </p>
 *
 * @author xjs
 */
@Service
public class SignRecordServiceImpl extends ServiceImpl<SignRecordMapper, SignRecord> implements ISignRecordService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RabbitMqHelper mqHelper;

    @Override
    public List<Integer> querySignRecord() {
        // 获取当前用户
        Long userId = UserContext.getUser();
        // 获取当前时间，年月日
        LocalDate now = LocalDate.now();
        // 获取redis中bitmap的key
        String key = getSignRecordKey(userId, now);
        // 查询从0天到当前所有的bit位
        List<Long> longs = redisTemplate.opsForValue().bitField(key,
                BitFieldSubCommands.create(
                        BitFieldSubCommands.BitFieldGet.create(BitFieldSubCommands.BitFieldType.unsigned(now.getDayOfMonth()),
                                BitFieldSubCommands.Offset.offset(0))));
        if(CollectionUtils.isEmpty(longs)){
            return new ArrayList<>();
        }
        int bitmapValue = longs.get(0).intValue();
        // 封装结果集
        List<Integer> result = new ArrayList<>();
        // 整数转化成二进制字符串
        String bitString = Integer.toBinaryString(bitmapValue);
        //从第0天到今天，计算是否签到过
        // 如果bit位数不够 用0补齐
        if(bitString.length() < now.getDayOfMonth()){
            bitString = StringUtils.leftPad(bitString,now.getDayOfMonth(),"0");
        }
        // 从第0天循环，看是0还是1
        for(int i=0;i < now.getDayOfMonth(); i++){
            char c = bitString.charAt(i);
            result.add(c=='1'?1:0);
        }
        return result;
    }

    @Override
    public SignResultVO sign() {
        // 获取当前用户
        Long userId = UserContext.getUser();
        // 获取当前时间，年月日
        LocalDate now = LocalDate.now();
        // 判断是否是重复签到，使用redis的bitmap，直接向bitmap做set操作，如果返回0说明签到成功
        String key = getSignRecordKey(userId, now);
        Boolean result = redisTemplate.opsForValue().setBit(key, now.getDayOfMonth() - 1, true);
        // 1（true）代表失败，0（false）代表成功
        if(result != null && result){
            // 如果是重复，结束
            throw new BizIllegalException("不能重复签到");
        }
        // 计算积分（签到的积分 + 连续签到送的积分）
        // 计算连续签到的天数
        // 从redis的bitmap中，获取从0天到当前天 所有的签到记录，转化成一个整数值
        List<Long> longs = redisTemplate.opsForValue().bitField(key,
                BitFieldSubCommands.create(
                        BitFieldSubCommands.BitFieldGet.create(BitFieldSubCommands.BitFieldType.unsigned(now.getDayOfMonth()),
                                BitFieldSubCommands.Offset.offset(0))));
        int bitmapValue = longs.get(0).intValue();
        // 计算连续签到的天数
        int count = countContinousSignDays(bitmapValue);
        // 计算奖励的积分
        int rewards = 0;
        if(count == 7){
            rewards = 10;
        }else if(count == 14){
            rewards = 20;
        }else if(count == 28){
            rewards = 40;
        }
        // 累加用户的积分
        PointsRecordMsgDTO msg = new PointsRecordMsgDTO();
        msg.setUserId(userId);
        msg.setType(PointsRecordType.SIGN.getValue());
        //1 + 奖励的积分
        msg.setPoints(1+rewards);
        mqHelper.send(LEARNING_EXCHANGE, POINT_RECORD_KEY, msg);

        // 组装结果集返回
        SignResultVO vo = new SignResultVO();
        vo.setRewardPoints(rewards);
        vo.setSignDays(count);
        return vo;
    }


    private int countContinousSignDays(int value){
        int count = 0;
        // 把整数值转化成二进制的字符串
        String binaryString = Integer.toBinaryString(value);
        // 从后往前数
        for(int i=binaryString.length()-1; i>=0; i--){
            char c = binaryString.charAt(i);
            if(c=='1'){
                count++;
            }else{
                break;
            }
        }
        return count;
    }
    /**
     * key：  prefix:userId:202401
     * */
    private String getSignRecordKey(Long userId, LocalDate now) {
        return SIGN_RECORD_KEY + userId+":" + DateUtils.format(now, "yyyyMM");
    }
}
